#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <linux/input.h>

#include "taiic_key.h"
#include "rk_debug.h"
#include "rk_defines.h"
#include <iostream>
#include <cstring> // 用于 strlen 和 strcpy

// 支持最大同按下的按键数量
#define KEY_COMBINATION 10

// 长按按键时会反复触发事件,这里设置时间间隔ms,为0时不触发长按事件
#define KEY_HOLD_EVENT_INTERVALMS 0
std::atomic<bool> stop_thread(false);

// 本地主结构体
typedef struct
{
    int fd[4];
    TAIIC_KEY_STATE key_old_state[4];
    void (*callback)(TAIIC_KEY_STATE, TAIIC_KEY_NAME, TAIIC_KEY_STATE);
} Key_Struct;

// 电量查询结构体
typedef struct
{
    /* data */
    // int fd;
    void (*callback)(int power_cap, long power_vol); // 电量查询回调函数
} Power_Struct;

// 回调线程传入参数结构体(就是把一堆参数打包成一个好传递)
typedef struct
{

    TAIIC_KEY_NAME key_name;   // 按键名字
    TAIIC_KEY_STATE key_state; //
    TAIIC_KEY_STATE old_state;
    void (*callback)(TAIIC_KEY_STATE, TAIIC_KEY_NAME, TAIIC_KEY_STATE);
    // 数组指针
    int *combin;
} Key_Param;

// 延时工具
#include <sys/time.h>
void key_delayms(unsigned int ms)
{
    struct timeval tv;
    tv.tv_sec = ms / 1000;
    tv.tv_usec = ms % 1000 * 1000;
    select(0, NULL, NULL, NULL, &tv);
}

// 抛线程工具
void throwOut_thread(void *obj, void *(*callback)(void *))
{
    pthread_t th;
    pthread_attr_t attr;
    // attr init
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); // 禁用线程同步, 线程运行结束后自动释放
    // 抛出线程
    pthread_create(&th, &attr, callback, (void *)obj);
    // attr destroy
    pthread_attr_destroy(&attr);
}

// 回调线程,在这里回调用户传入的callback函数
static void *key_callback(void *argv)
{
    Key_Param *kp = (Key_Param *)argv;
    do
    {
        // 按键事件回调
        if (kp->callback)
        {
            if (kp->key_state != kp->old_state)
            {
                kp->callback(kp->old_state, kp->key_name, kp->key_state);
                // RK_LOGI("=====callback call success====\n");
            }
        }

        // 该值为0时,不触发长按事件
        if (KEY_HOLD_EVENT_INTERVALMS > 0)
        {
            // 抬起事件,经过2倍延时后切换为长按事件
            if (kp->key_state == TAIIC_KEY_UP)
            {
                key_delayms(KEY_HOLD_EVENT_INTERVALMS * 2);
                kp->key_state = TAIIC_KEY_HOLD;
            }
            // 长按事件
            else if (kp->key_state == TAIIC_KEY_HOLD)
                key_delayms(KEY_HOLD_EVENT_INTERVALMS);
        }
        // 周期触发长按事件
    } while (kp->key_state == TAIIC_KEY_HOLD && kp->combin[0] == kp->key_state);
    free(kp);
    return ((void *)0);
}

// 数组元素的设置和清除,返回位置
static int _arrayAdd(int *array, int len, int value)
{
    int i;
    for (i = 0; i < len; i++)
    {
        // RK_LOGI("=====array is %d======\n",array[i]);
        if (array[i] == 0)
        {
            array[i] = value;
            return i;
        }
    }
    return 0;
}
static int _arrayClear(int *array, int len, int value)
{
    int i;
    for (i = 0; i < len; i++)
    {
        // RK_LOGI("=====array is %d======\n",array[i]);
        if (array[i] == value)
        {
            array[i] = 0;
            return i;
        }
    }
    return 0;
}

static void *key_thread(void *argv)
{
    Key_Struct *ks = (Key_Struct *)argv;
    Key_Param *kp;

    char value_str[4];
    int order;
    int retRead;
    int combin[KEY_COMBINATION] = {0};
    for (;;)
    {
        // 阻塞读
        //  RK_LOGI("retRead begin !!!\r\n");
        for (int i = 0; i < 4; i++)
        // for (int i = 2;i<3;i++)
        {
            retRead = read(ks->fd[i], value_str, 4);
            // RK_LOGI("retRead : %d\r\n", retRead);
            lseek(ks->fd[i], 0, SEEK_SET);
            if (retRead > 0)
            {
                // 按键按下时注册到数组,释放时清除
                order = 0;
                // RK_LOGI("=====key value is %d=====\n",atoi(value_str));
                if (atoi(value_str) == 1) // 电位发生变化
                {
                    order = _arrayAdd(combin, KEY_COMBINATION, atoi(value_str));
                    // RK_LOGI("=======array add %d =======\n",order);
                }
                else
                {
                    _arrayClear(combin, KEY_COMBINATION, atoi(value_str));
                    // RK_LOGI("=======array clear=======\n");
                }
                // 参数准备
                kp = (Key_Param *)calloc(1, sizeof(Key_Param));
                // RK_LOGI("======order is %d====\n", order);

                kp->key_name = (TAIIC_KEY_NAME)i;                      // 键位
                kp->key_state = (TAIIC_KEY_STATE)atoi(value_str);      // 键值
                kp->old_state = (TAIIC_KEY_STATE)ks->key_old_state[i]; //
                kp->callback = ks->callback;
                kp->combin = &combin[order];
                // 抛线程,在异步线程中触发用户回调函数
                //  RK_LOGI("=====key throwOut_thread start =====\n");
                throwOut_thread(kp, &key_callback);
                ks->key_old_state[i] = (TAIIC_KEY_STATE)atoi(value_str);
                // RK_LOGI("=====key throwOut_thread end =====\n");
            }
        }
        usleep(10000); // 间隔10ms
    }
}

/*
 *  按键回调注册
 *  参数:
 *      obj: 用户私有指针,会在互调的时候传回给用户
 *      callback: 回调函数原型 void callback(void *obj, int key, int type)
 *  回调函数参数:
 *      obj: 前面传入的用户私有指针
 *      key: 键位值,可以看<linux/input.h>中的定义,或者先测试打印一遍就知道哪个按键对哪个值了
 *      type: 按键状态,0/松开时,1/按下时,2/一直按住(会反复触发回调)
 *  返回: 0/成功 -1/失败,找不到设备或者没有sudo运行
 */

int taiic_key_register(TAIIC_KEY_STATE *old_state, tKeyValueCallback callback)
{
    Key_Struct *ks;
    int fd[4];
    // 关键参数检查
    if (!callback)
        return -1;
    // 只读打开键盘所在input设备
    fd[0] = open(SYSFS_GPIO_MODE, O_RDONLY);
    fd[1] = open(SYSFS_GPIO_AUDIO, O_RDONLY);
    fd[2] = open(SYSFS_GPIO_PTT, O_RDONLY);
    fd[3] = open(SYSFS_GPIO_MODE1, O_RDONLY);

    // fd = open(SYSFS_POWER, O_RDONLY); //监听电源键

    if (fd[0] < 1 || fd[1] < 1 || fd[2] < 1 || fd[3] < 1)
    {
        RK_LOGE("key_register: open failed\r\n");
        return -1;
    }
    RK_LOGD("======open file success========\n");
    // 参数备份,抛线程检测按键
    ks = (Key_Struct *)calloc(1, sizeof(Key_Struct));
    for (int i = 0; i < 4; i++)
    {
        ks->fd[i] = fd[i];                                    // open file
        ks->key_old_state[i] = (TAIIC_KEY_STATE)old_state[i]; // key_old_state
    }
    ks->callback = callback;
    throwOut_thread(ks, &key_thread);
    return 0;
}

// 读取键值
TAIIC_KEY_STATE taiic_gpio_read(int key_name)
{
    int fd;
    char path[64];
    char value_str[4];
    if (key_name == TAIIC_KEY_NAME::TAIIC_MODE)
    {
        snprintf(path, sizeof(path), SYSFS_GPIO_MODE);
    }
    else if (key_name == TAIIC_KEY_NAME::TAIIC_AUDIO)
    {
        snprintf(path, sizeof(path), SYSFS_GPIO_AUDIO);
    }
    else if (key_name == TAIIC_KEY_NAME::TAIIC_PTT)
    {
        snprintf(path, sizeof(path), SYSFS_GPIO_PTT);
    }
    else if (key_name == TAIIC_KEY_NAME::TAIIC_MODE1)
    {
        snprintf(path, sizeof(path), SYSFS_GPIO_MODE1);
    }

    fd = open(path, O_RDONLY);

    if (read(fd, value_str, 4) < 0)
    {
        RK_LOGE("Failed to read value!\n");
        return TAIIC_KEY_NOVALUE;
    }
    close(fd);
    // RK_LOGI("======%s key is %d=====\n", path, atoi(value_str));
    return ((TAIIC_KEY_STATE)atoi(value_str));
}

void keyboard_event_listener(const char *device_path, tKeyValueCallback callback)
{
    if(!callback)
        return;
    int fd = open(device_path, O_RDONLY);
    if (fd == -1)
    {
        std::cerr << "无法打开输入设备: " << device_path << " - " << strerror(errno) << std::endl;
        return;
    }

    struct input_event ev;
    std::cout << "开始监听键盘事件..." << std::endl;

    while (!stop_thread)
    {
        // 设置超时时间（例如 100 毫秒）
        fd_set fds;
        FD_ZERO(&fds);
        FD_SET(fd, &fds);
        struct timeval timeout;
        timeout.tv_sec = 0;
        timeout.tv_usec = 200000;  // 200ms

        // 等待设备可读或超时
        int ret = select(fd + 1, &fds, nullptr, nullptr, &timeout);
        if (ret == -1) {
            std::cerr << "select 错误: " << strerror(errno) << std::endl;
            break;
        } else if (ret == 0) {
            // 超时，继续循环
            continue;
        }

        ssize_t bytes = read(fd, &ev, sizeof(ev));
        if (bytes == -1)
        {
            if (errno == EINTR)
                continue;
            std::cerr << "读取错误: " << strerror(errno) << std::endl;
            break;
        }

        if (bytes != sizeof(ev))
        {
            std::cerr << "读取不完整的事件" << std::endl;
            continue;
        }

        // 只处理按键事件
        if (ev.type == EV_KEY)
        {
            // 获取按键状态
            TAIIC_KEY_STATE key_state;
            switch (ev.value)
            {
            case 0:
                key_state = TAIIC_KEY_UP;
                break;
            case 1:
                key_state = TAIIC_KEY_DOWN;
                break;
            }

            // 获取按键名称
            const char *key_name = "PTT";
            /*
            std::cout << "按键事件: " << key_name
                      << " 状态: " << key_state
                      << " 代码: " << ev.code << std::endl;
            */
            callback(key_state, TAIIC_PTT, key_state);
        }
    }

    close(fd);
}

// 注册所有按键
int taiic_all_key_registers(TAIIC_MODE_STATE_CTX_S *ctx, tKeyValueCallback keyCallback)
{
    TAIIC_KEY_STATE old_mode_state = taiic_gpio_read(TAIIC_MODE); // 获取模式初始状态,语音
    ctx->mode_flag = (ctx->mode_flag == old_mode_state) ? ctx->mode_flag : old_mode_state;
    RK_LOGI("--------------user_model-----------------------%d\n", ctx->mode_flag);

    TAIIC_KEY_STATE old_mode1_state = taiic_gpio_read(TAIIC_MODE1); // 获取模式初始状态,唇图
    ctx->mode1_flag = (ctx->mode1_flag == old_mode1_state) ? ctx->mode1_flag : old_mode1_state;
    RK_LOGI("--------------user_model1-----------------------%d\n", ctx->mode1_flag);

    TAIIC_KEY_STATE old_audio_state = taiic_gpio_read(TAIIC_AUDIO); // 获取音频线的状态，插入vs拔出
    ctx->audio_flag = (ctx->audio_flag == old_audio_state) ? ctx->audio_flag : old_audio_state;
    RK_LOGI("---------------audio_flag-----------------------%d\n", ctx->audio_flag);

    TAIIC_KEY_STATE old_ptt_state = taiic_gpio_read(TAIIC_PTT); // 获取ptt的状态，抬起vs按下
    ctx->ptt_flag = (ctx->ptt_flag == old_ptt_state) ? ctx->ptt_flag : old_ptt_state;
    RK_LOGI("---------------ptt_flg-----------------------%d\n", ctx->ptt_flag);

    // 动监听全包·耳机的ptt线程
    std::thread listener_ptt_thread(keyboard_event_listener, SYSFS_DEVICE_PTT, keyCallback);
    listener_ptt_thread.detach();

    TAIIC_KEY_STATE state_list[4]; // TAIIC_KEY_STATE state_list[3];
    state_list[0] = old_mode_state;
    state_list[1] = old_audio_state;
    state_list[2] = old_ptt_state;
    state_list[3] = old_mode1_state;
    taiic_key_register(state_list, keyCallback);
    return 0;
}

static void *power_thread(void *argv)
{
    Power_Struct *ps = (Power_Struct *)argv;
    char tmpCap[3];   // 电量查询值
    char tmpVol[10];  // 电池电压查询值
    int compCap = -1; // 本次电量与上次电量对比值
    int fd1 = 0;
    int fd2 = 0;

    for (;;)
    {
        RK_LOGD("===reread==\n");
        fd1 = open(SYSFS_BATTERY_CAP, O_RDONLY);
        if (read(fd1, tmpCap, 3) < 0)
        {
            RK_LOGE("Failed to read capacity value!\n");
            continue;
        }
        close(fd1);
        fd2 = open(SYSFS_BATTERY_VOLTAGE, O_RDONLY);
        if (read(fd2, tmpVol, 10) < 0)
        {
            RK_LOGE("Failed to read voltage value!\n");
            continue;
        }
        close(fd2);
        if (atoi(tmpCap) != compCap && ps->callback)
        {
            ps->callback(atoi(tmpCap), atoi(tmpVol));
            compCap = atoi(tmpCap);
        }

        // int retRead = read(ps->fd, tmpCap, 3);
        // lseek(ps->fd, 0, SEEK_SET);
        // if(retRead > 0 && ps->callback && atoi(tmpCap) != compCap && tmpCap != NULL)
        // {
        //     ps->callback(atoi(tmpCap));
        //     compCap = atoi(tmpCap);
        // }
        // sleep(HOLD_TIME); // 间隔200s
        sleep(1); // 间隔200s

        // 阻塞读取电量值
        //  ps->fd = fopen(SYSFS_BATTERY_CAP, "r");
        //  fscanf(ps->fd, "%d\n", &tmpCap); //读取设备电量
        //  fclose(ps->fd);
        //  if(tmpCap != NULL && tmpCap != ps->cap)
        //  {
        //      if(ps->callback)
        //      {
        //          ps->callback(tmpCap);
        //      }
        //      ps->cap = tmpCap;
        //  }
        //  usleep(60000000); //间隔60s
    }
    free(ps);
}

int taiic_batt_power_registers(tPowerValueCallback powerCallback)
{
    Power_Struct *ps;
    ps = (Power_Struct *)calloc(1, sizeof(Power_Struct));

    // ps->fd = fp;
    // ps->cap = atoi(tmpCap);
    ps->callback = powerCallback;

    throwOut_thread(ps, &power_thread);
    return 0;
}

// 获取Linux命令的返回结果
void ExecCmd(char *in, char out[])
{
    FILE *fp = NULL;
    fp = popen(in, "r");
    if (fp)
    {
        int ret = fread(out, 1, sizeof(out) - 1, fp);
        // if(ret > 0) {
        //     printf("Execute result:%s\n",out);
        // }
        pclose(fp);
    }
}

// 将两个字符串拼接成一个字符串
char *concatenate(const char *str1, const char *str2)
{
    // 计算新字符串的长度
    size_t len1 = strlen(str1);
    size_t len2 = strlen(str2);
    // 分配足够的内存来存储新字符串（包括结束符 '\0'）
    char *result = new char[len1 + len2 + 1];
    // 复制字符串到新内存
    std::strcpy(result, str1);
    std::strcpy(result + len1, str2);
    // 返回新字符串
    return result;
}
